//检测浏览器是否支持DOM2级XML
function hasXmlDom() {
    var hasXmlDom = document.implementation.hasFeature("XML", "2.0");
    console.log("hasXmlDom:" + hasXmlDom);
}

function createDocumentTest() {
    var xmldom = document.implementation.createDocument("", "root", null);
    alert(xmldom.documentElement.tagName); //"root"
    var child = xmldom.createElement("child");
    xmldom.documentElement.appendChild(child);
    var child2 = xmldom.createElement("child");
    xmldom.documentElement.appendChild(child2);
    var subchild = xmldom.createElement("subchild");
    child2.appendChild(subchild);
    return xmldom;
}

function DOMParserTest() {
    var parser = new DOMParser();
    var xmldom = parser.parseFromString("<root><child/></root>", "text/xml");
    alert(xmldom.documentElement.tagName); //"root"
    alert(xmldom.documentElement.firstChild.tagName); //"child"
    var anotherChild = xmldom.createElement("child");
    xmldom.documentElement.appendChild(anotherChild);
    var children = xmldom.getElementsByTagName("child");
    alert(children.length); //2
}

function DOMParserErrorTest() {
    var parser = new DOMParser(),
        xmldom,
        errors;
    try {
        xmldom = parser.parseFromString("<root>", "text/xml");
        errors = xmldom.getElementsByTagName("parsererror");
        if (errors.length > 0) {
            console.error(errors[0].textContent);
            throw new Error("Parsing error!");
        }
    } catch (ex) {
        alert("Parsing error!");
    }
}

function XMLSerializerTest(xmldom) {
    var serializer = new XMLSerializer();
    var xml = serializer.serializeToString(xmldom);
    alert(xml);
}

function loadXMLTest() {
    if (typeof ActiveXObject !== "undefined") {
        //IE支持
        var xmldom = createDocument();
        xmldom.async = false;
        xmldom.load("../file/example.xml");
        if (xmldom.parseError !== 0) {
            //处理错误
            console.log("error");
        } else {
            alert(xmldom.documentElement.tagName); //"root"
            alert(xmldom.documentElement.firstChild.tagName); //"child"
            var anotherChild = xmldom.createElement("child");
            xmldom.documentElement.appendChild(anotherChild);
            var children = xmldom.getElementsByTagName("child");
            alert(children.length); //2
            alert(xmldom.xml);
        }
    } else {
        alert("浏览器不支持");
    }
}

function parseXmlTest() {
    var xmldom = null;
    try {
        xmldom = parseXml("<root><child/></root>");
    } catch (ex) {
        alert(ex.message);
    }
    alert(xmldom.documentElement.tagName); //"root"
    alert(xmldom.documentElement.firstChild.tagName); //"child"
    var anotherChild = xmldom.createElement("child");
    xmldom.documentElement.appendChild(anotherChild);
    var children = xmldom.getElementsByTagName("child");
    alert(children.length); //2
    alert(serializeXml(xmldom));
}

function parseXml(xml) {
    var xmldom = null;
    if (typeof DOMParser !== "undefined") {
        xmldom = (new DOMParser()).parseFromString(xml, "text/xml");
        var errors = xmldom.getElementsByTagName("parsererror");
        if (errors.length) {
            throw new Error("XML parsing error:" + errors[0].textContent);
        }
    } else if (typeof ActiveXObject !== "undefined") {
        xmldom = createDocument();
        xmldom.loadXML(xml);
        if (xmldom.parseError !== 0) {
            throw new Error("XML parsing error: " + xmldom.parseError.reason);
        }
    } else {
        throw new Error("No XML parser available.");
    }
    return xmldom;
}

function serializeXml(xmldom) {
    if (typeof XMLSerializer !== "undefined") {
        return (new XMLSerializer()).serializeToString(xmldom);
    } else if (typeof xmldom.xml !== "undefined") {
        return xmldom.xml;
    } else {
        throw new Error("Could not serialize XML DOM.");
    }
}

function supportsXPathTest() {
    var btn = document.getElementById("supportsXPath");
    var supportsXPath = document.implementation.hasFeature("XPath", "3.0");
    if (supportsXPath) {
        // btn.style.backgroundColor = "greenyellow";
        btn.className = "green-bg";
    } else {
        // btn.style.backgroundColor = "orangered";
        btn.className = "red-bg";
    }
    alert("supportsXPath:" + supportsXPath);
}

function XPathIterateTest() {
    var xmldom = createDocumentTest();
    console.log(serializeXml(xmldom));
    var result = xmldom.evaluate("employee/name", xmldom.documentElement, null,
        XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
    if (result !== null) {
        var node = result.iterateNext();
        while (node) {
            alert(node.tagName);
            node = node.iterateNext();
        }
    }
}

function XPathSnapshotTest() {
    var xmldom = createDocumentTest();
    console.log(serializeXml(xmldom));
    var result = xmldom.evaluate("root/child", xmldom.documentElement, null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    if (result !== null) {
        for (var i = 0, len = result.snapshotLength; i < len; i++) {
            alert(result.snapshotItem(i).tagName);
        }
    }
}

function XPathSingleNodeTest() {
    var xmldom = parseXml("<root><child/></root>");
    console.log(serializeXml(xmldom));
    var result = xmldom.evaluate("root", xmldom.documentElement, null,
        XPathResult.FIRST_ORDERED_NODE_TYPE, null);
    if (result !== null) {
        alert(result.singleNodeValue.tagName);
    }
}

function XPathTypeTest() {
    var xmldom = parseXml("<root><child/><child/><subchild>stringTest</subchild></root>");
    var result = xmldom.evaluate("child", xmldom.documentElement, null,
        XPathResult.BOOLEAN_TYPE, null);
    console.log(result.booleanValue);
    var result = xmldom.evaluate("count(child)", xmldom.documentElement,
        null, XPathResult.NUMBER_TYPE, null);
    console.log(result.numberValue);
    var result = xmldom.evaluate("subchild", xmldom.documentElement, null,
        XPathResult.STRING_TYPE, null);
    console.log(result.stringValue);
}

function XPathAnyType(xmldom, expression) {
    var result = xmldom.evaluate(expression, xmldom.documentElement, null,
        XPathResult.ANY_TYPE, null);
    if (result !== null) {
        console.log(result.resultType);
        switch (result.resultType) {
            case XPathResult.STRING_TYPE:
                //处理字符串类型
                console.log("处理字符串类型");
                break;
            case XPathResult.NUMBER_TYPE:
                //处理数值类型
                console.log("处理数值类型");
                break;
            case XPathResult.BOOLEAN_TYPE:
                //处理布尔值类型
                console.log("处理布尔值类型");
                break;
            case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
                //处理次序不一致的节点迭代器类型
                console.log("处理次序不一致的节点迭代器类型");
                break;
            default:
                //处理其他可能的结果类型
                console.log("处理其他可能的结果类型");
        }
    }
}

function XPathAnyTypeTest() {
    var xmldom1 = parseXml("<root><child/></root>");
    XPathAnyType(xmldom1, "root");
}

function selectSingleNode(context, expression, namespaces) {
    var doc = (context.nodeType != 9 ? context.ownerDocument : context);
    if (typeof doc.evaluate != "undefined") {
        var nsresolver = null;
        if (namespaces instanceof Object) {
            nsresolver = function (prefix) {
                return namespaces[prefix];
            };
        }
        var result = doc.evaluate(expression, context, nsresolver,
            XPathResult.FIRST_ORDERED_NODE_TYPE, null);
        return (result !== null ? result.singleNodeValue : null);
    } else if (typeof context.selectSingleNode != "undefined") {
        //创建命名空间字符串
        if (namespaces instanceof Object) {
            var ns = "";
            for (var prefix in namespaces) {
                if (namespaces.hasOwnProperty(prefix)) {
                    ns += "xmlns:" + prefix + "='" + namespaces[prefix] + "' ";
                }
            }
            doc.setProperty("SelectionNamespaces", ns);
        }
        return context.selectSingleNode(expression);
    } else {
        throw new Error("No XPath engine found.");
    }
}

function selectNodes(context, expression, namespaces) {
    var doc = (context.nodeType != 9 ? context.ownerDocument : context);
    if (typeof doc.evaluate != "undefined") {
        var nsresolver = null;
        if (namespaces instanceof Object) {
            nsresolver = function (prefix) {
                return namespaces[prefix];
            };
        }
        var result = doc.evaluate(expression, context, nsresolver,
            XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
        var nodes = [];
        if (result !== null) {
            for (var i = 0, len = result.snapshotLength; i < len; i++) {
                nodes.push(result.snapshotItem(i));
            }
        }
        return nodes;
    } else if (typeof context.selectNodes != "undefined") {
        //创建命名空间字符串
        if (namespaces instanceof Object) {
            var ns = "";
            for (var prefix in namespaces) {
                if (namespaces.hasOwnProperty(prefix)) {
                    ns += "xmlns:" + prefix + "='" + namespaces[prefix] + "' ";
                }
            }
            doc.setProperty("SelectionNamespaces", ns);
        }
        var result = context.selectNodes(expression);
        var nodes = [];
        for (var i = 0, len = result.length; i < len; i++) {
            nodes.push(result[i]);
        }
        return nodes;
    } else {
        throw new Error("No XPath engine found.");
    }
}
